
package com.hlkj.pay.app.merchant.ext.impl.yftpay.ext;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import cn.hutool.json.JSONObject;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.yftpay.constant.YftPayConstant;
import com.hlkj.pay.app.merchant.ext.impl.yftpay.dto.YftPayConfig;
import com.hlkj.pay.app.merchant.ext.impl.yftpay.dto.YftpayAppChannelParams;
import com.hlkj.pay.app.merchant.ext.impl.yftpay.utils.HttpUtils;
import com.hlkj.pay.app.merchant.ext.impl.yftpay.utils.PayDigestUtilOK;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.order.RefundOrderDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.util.MerchantUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

/**
 * 银付通 正扫 反扫 通用处理
 * 
 * @author HlpayTeam
 * @date 2024/10/11 16:22
 */
@Slf4j
@Repository
@RequiredArgsConstructor
public class YftPaySceneCommonPayOrder {

    /**
     * 银付通查询支付订单
     *
     * @param channelPayOrderQueryContext
     */
    public void commonQueryChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        ProviderChannelConfigDO providerChannelConfigDO = channelPayOrderQueryContext.getProviderChannelConfigDO();
        String channelConfig = providerChannelConfigDO.getParamsConfig();
        // 配置转换
        YftPayConfig yftPayConfig = getPayConfig(channelConfig, channelPayOrderQueryContext.getMerchantAppChannelDO());

        PayOrderDO payOrderDO = channelPayOrderQueryContext.getPayOrderDO();
        try {

            JSONObject paramMap = new JSONObject();
            paramMap.set("mchId", yftPayConfig.getMchId());                               // 商户ID
//            paramMap.set("appId", yftPayConfig.getAppId());
            paramMap.set("mchOrderNo", payOrderDO.getPayOrderNo());                     // 商户订单号
            paramMap.set("executeNotify", "false");                      // 是否执行回调,true或false,如果为true当订单状态为支付成功(2)时,支付中心会再次回调一次业务系统

            String reqSign = PayDigestUtilOK.getSign(paramMap, yftPayConfig.getMd5Key());
            paramMap.set("sign", reqSign);                              // 签名
            String reqData = "params=" + paramMap.toString();

            log.info("银付通订单查询req参数:{}", reqData);
            String url = domain(channelPayOrderQueryContext.isTest()) + YftPayConstant.TRADE_QUERY;
            String response = HttpUtils.get(url + "?" + reqData);
            log.info("银付通订单查询返回参数:{}", response);

            // 响应报文验签
            JSONObject ordeRsp = JsonUtils.parseObj(response);
            if ("SUCCESS".equals(ordeRsp.getStr("retCode"))) {
                PayOrderDO updartePayOrderDO = new PayOrderDO();
                switch (ordeRsp.getInt("status")) {
                    case 2:
                        updartePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode());
                        break;
                    case 0:
                    case 1:
                    case 3:
                        updartePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.PAYING.getCode());
                        break;
                    default:
                        updartePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.FAIL.getCode());
                }

                updartePayOrderDO.setInsOrderNo(ordeRsp.getStr("payOrderId"));
                updartePayOrderDO.setChannelOrderNo(ordeRsp.getStr("channelOrderNo"));
                updartePayOrderDO.setUserId(ordeRsp.getStr("channelUser"));
                if (ordeRsp.containsKey("paySuccTime")) {
                    updartePayOrderDO.setSuccessTime(ordeRsp.getLong("paySuccTime"));
                }
                channelPayOrderQueryContext.setUpdartePayOrderDO(updartePayOrderDO);
            }
            else {
                String respDesc = ordeRsp.getStr("retMsg");
                channelPayOrderQueryContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    channelPayOrderQueryContext.setRemark(respDesc);
                }
                else {
                    channelPayOrderQueryContext.setRemark("银付通提交支付订单查询返回错误信息为空,错误码为:" + ordeRsp.getStr("retCode"));
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("银付通查询支付订单请求失败 message:{}", e.getMessage(), e);
            channelPayOrderQueryContext.setRemark("银付通查询支付订单请求失败,失败信息" + e.getMessage());
            channelPayOrderQueryContext.setProcessStatus(Boolean.FALSE);
        }
    }

    /**
     * 银付通关闭订单
     *
     * @param channelPayOrderQueryContext
     */
    public void commonCloseChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
    }

    /**
     * 银付通查询关闭订单状态
     *
     * @param channelPayOrderQueryContext
     */
    public void commonQueryChannelClosePayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        // 银付通无此接口
        PayOrderDO updartePayOrderDO = new PayOrderDO();
        updartePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.CLOSE.getCode());
        channelPayOrderQueryContext.setUpdartePayOrderDO(updartePayOrderDO);
    }

    /**
     * 银付通订单退款
     *
     * @param channelRefundPayOrderContext
     */
    public void commonRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        ProviderChannelConfigDO providerChannelConfigDO = channelRefundPayOrderContext.getProviderChannelConfigDO();
        String channelConfig = providerChannelConfigDO.getParamsConfig();
        // 配置转换
        YftPayConfig yftPayConfig = getPayConfig(channelConfig, channelRefundPayOrderContext.getMerchantAppChannelDO());

        PayOrderDO payOrderDO = channelRefundPayOrderContext.getPayOrderDO();
        RefundOrderDO refundOrderDO = channelRefundPayOrderContext.getRefundOrderDO();
        try {

            JSONObject paramMap = new JSONObject();
            paramMap.set("mchId", yftPayConfig.getMchId());                               // 商户ID
            paramMap.set("mchOrderNo", payOrderDO.getPayOrderNo());                     // 商户订单号
            paramMap.set("mchRefundNo", refundOrderDO.getRefundOrderNo());                      // 是否执行回调,true或false,如果为true当订单状态为支付成功(2)时,支付中心会再次回调一次业务系统
            paramMap.set("amount", MerchantUtils.YuanToFen(refundOrderDO.getRefundAmount()).toString());
            paramMap.set("currency", "cny");
            paramMap.set("notifyUrl", channelRefundPayOrderContext.getNotifyUrl());
            paramMap.set("channelUser", refundOrderDO.getRefundOrderNo());

            String reqSign = PayDigestUtilOK.getSign(paramMap, yftPayConfig.getMd5Key());
            paramMap.set("sign", reqSign);                              // 签名
            String reqData = "params=" + paramMap.toString();

            log.info("银付通订单退款req参数:{}", reqData);
            String url = domain(channelRefundPayOrderContext.isTest()) + YftPayConstant.REFUND_ORDER;
            String response = HttpUtils.post(url, paramMap);
            log.info("银付通订单退款返回参数:{}", response);

            JSONObject ordeRsp = JsonUtils.parseObj(response);
            if ("SUCCESS".equals(ordeRsp.getStr("retCode"))) {
                RefundOrderDO updateRefundOrderDO = new RefundOrderDO();
                if ("2".equals(ordeRsp.getStr("status")) || "4".equals(ordeRsp.getStr("status"))) {
                    updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUND.getCode());
                    updateRefundOrderDO.setSuccessTime(System.currentTimeMillis());
                } else
                    updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUNDING.getCode());

                channelRefundPayOrderContext.setUpdateRefundOrderDO(updateRefundOrderDO);
            }
            else {
                String respDesc = ordeRsp.getStr("retMsg");
                channelRefundPayOrderContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    channelRefundPayOrderContext.setRemark(respDesc);
                }
                else {
                    channelRefundPayOrderContext.setRemark("银付通提交退款订单返回错误信息为空,错误码为:" + ordeRsp.getStr("retCode"));
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("银付通提交退款订单请求失败 message:{}", e.getMessage(), e);
            channelRefundPayOrderContext.setRemark("银付通提交退款订单请求失败,失败信息" + e.getMessage());
            channelRefundPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    /**
     * 银付通订单退款状态查询
     *
     * @param channelRefundPayOrderContext
     */
    public void commonQueryRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        ProviderChannelConfigDO providerChannelConfigDO = channelRefundPayOrderContext.getProviderChannelConfigDO();
        String channelConfig = providerChannelConfigDO.getParamsConfig();
        // 配置转换
        YftPayConfig yftPayConfig = getPayConfig(channelConfig, channelRefundPayOrderContext.getMerchantAppChannelDO());

        RefundOrderDO refundOrderDO = channelRefundPayOrderContext.getRefundOrderDO();
        try {

            JSONObject paramMap = new JSONObject();
            paramMap.set("mchId", yftPayConfig.getMchId());                               // 商户ID
            paramMap.set("mchRefundNo", refundOrderDO.getRefundOrderNo());                      // 是否执行回调,true或false,如果为true当订单状态为支付成功(2)时,支付中心会再次回调一次业务系统

            String reqSign = PayDigestUtilOK.getSign(paramMap, yftPayConfig.getMd5Key());
            paramMap.set("sign", reqSign);                              // 签名
            String reqData = "params=" + paramMap.toString();

            log.info("银付通订单退款查询req参数:{}", reqData);
            String url = domain(channelRefundPayOrderContext.isTest()) + YftPayConstant.REFUND_QUERY;
            String response = HttpUtils.post(url, paramMap);
            log.info("银付通订单退款查询返回参数:{}", response);

            JSONObject ordeRsp = JsonUtils.parseObj(response);
            if ("SUCCESS".equals(ordeRsp.getStr("retCode"))) {
                RefundOrderDO updateRefundOrderDO = new RefundOrderDO();
                switch (ordeRsp.getInt("status")) {
                    case 2:
                    case 4:
                        updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUND.getCode());
                        break;
                    case 3:
                        updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.FAIL.getCode());
                        break;
                    default:
                        updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUNDING.getCode());
                        break;
                }
                channelRefundPayOrderContext.setUpdateRefundOrderDO(updateRefundOrderDO);
            }
            else {
                String respDesc = ordeRsp.getStr("retMsg");
                channelRefundPayOrderContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    channelRefundPayOrderContext.setRemark(respDesc);
                }
                else {
                    channelRefundPayOrderContext.setRemark("银付通提交退款订单返回错误信息为空,错误码为:" + ordeRsp.getStr("retCode"));
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("银付通退款订单查询请求失败 message:{}", e.getMessage(), e);
            channelRefundPayOrderContext.setRemark("银付通退款订单查询请求失败,失败信息" + e.getMessage());
            channelRefundPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    public YftpayAppChannelParams dffPayAppChannelParams(MerchantAppChannelDO merchantAppChannelDO) {
        return JsonUtils.parseObject(merchantAppChannelDO.getAppConfigJson(), YftpayAppChannelParams.class);
    }

    public String domain(boolean test) {
        return YftPayConstant.PAY_ORDER_DOMAIN_PROD;
    }

    public Integer expireMinute(Long time) {
        if (time == null) {
            return 30;
        }
        return (int) (time - System.currentTimeMillis()) / 1000 / 60;
    }

    public YftPayConfig getPayConfig(String channelConfig, MerchantAppChannelDO merchantAppChannelDO) {
        // 配置转换
        YftPayConfig yftPayConfig = JsonUtils.parseObject(channelConfig, YftPayConfig.class);

        YftpayAppChannelParams yftpayAppChannelParams = dffPayAppChannelParams(merchantAppChannelDO);

        if (StringUtils.hasText(yftpayAppChannelParams.getMchId()))
            yftPayConfig.setMchId(yftpayAppChannelParams.getMchId());

        if (StringUtils.hasText(yftpayAppChannelParams.getMd5Key()))
            yftPayConfig.setMd5Key(yftpayAppChannelParams.getMd5Key());
        return yftPayConfig;
    }

}
